#pragma once

#include "common.h"

#ifdef LITTLE_ENDIAN
#define BITSWAP16(x) (((x << 8) & 0xff00) | ((x >> 8) & 0x00ff))

#define BITSWAP32(x) (((x << 24) & 0xff000000) | ((x <<  8) & 0x00ff0000) | \
					  ((x >>  8) & 0x0000ff00) | ((x >> 24) & 0x000000ff))

#define BITSWAP64(x) (((x << 56) & 0xff00000000000000ULL) | ((x << 40) & 0x00ff000000000000ULL) | \
					 ((x << 24) & 0x0000ff0000000000ULL) | ((x <<  8) & 0x000000ff00000000ULL) | \
					 ((x >>  8) & 0x00000000ff000000ULL) | ((x >> 24) & 0x0000000000ff0000ULL) | \
					 ((x >> 40) & 0x000000000000ff00ULL) | ((x >> 56) & 0x00000000000000ffULL))
#else
#define BITSWAP16(x) (x)
#define BITSWAP32(x) (x)
#define BITSWAP64(x) (x)
#endif

class ByteBuffer
{
	friend class ByteBufferException;

public:

	ByteBuffer():_rpos(0), _wpos(0) { _storage.reserve(255); }
	ByteBuffer(const ByteBuffer &r):_rpos(r._rpos), _wpos(r._wpos), _storage(r._storage) {}
	ByteBuffer(const uint8* buf, size_t size);
	~ByteBuffer() {}

	ByteBuffer& operator= (const ByteBuffer& r);

	void Copy(vector<uint8>& dst){ dst = _storage; }
	void Clear()				 { _storage.clear(); _rpos = _wpos = 0; }
	const uint8* Data() const    { return &_storage[0]; }
	size_t Size() const			 { return _storage.size(); }
	size_t Left() const			 { return _storage.size() - _rpos; }

	void Append(const uint8 *src, uint16 size) { _Write(src, size); }
	void Reduce(uint8 *dest, uint16 size) { _Read(dest, size); }

	ByteBuffer& operator<<(int8 value)	 	{ _Write<int8>(value); return *this; }
	ByteBuffer& operator>>(int8 &value) 	{ _Read<int8>(value); return *this; }
	ByteBuffer& operator<<(uint8 value) 	{ _Write<uint8>(value); return *this; }
	ByteBuffer& operator>>(uint8 &value) 	{ _Read<uint8>(value); return *this; }

	ByteBuffer& operator<<(int16 value)	    { _Write<int16>(htons(value)); return *this; }
	ByteBuffer& operator>>(int16 &value)	{ _Read<int16>(value); value = ntohs(value); return *this; }
	ByteBuffer& operator<<(uint16 value)	{ _Write<uint16>(htons(value)); return *this; }
	ByteBuffer& operator>>(uint16 &value)	{ _Read<uint16>(value); value = ntohs(value); return *this; }

	ByteBuffer& operator<<(int32 value)		{ _Write<int32>(htonl(value)); return *this; }
	ByteBuffer& operator>>(int32 &value)	{ _Read<int32>(value); value = ntohl(value); return *this; }
	ByteBuffer& operator<<(uint32 value)	{ _Write<uint32>(htonl(value)); return *this; }
	ByteBuffer& operator>>(uint32 &value)	{ _Read<uint32>(value); value = ntohl(value); return *this; }

	ByteBuffer& operator<<(int64 value)		{ _Write<int64>(BITSWAP64(value)); return *this; }
	ByteBuffer& operator>>(int64 &value)	{ _Read<int64>(value); value = BITSWAP64(value); return *this; }
	ByteBuffer& operator<<(uint64 value)	{ _Write<uint64>(BITSWAP64(value)); return *this; }
	ByteBuffer& operator>>(uint64 &value)	{ _Read<uint64>(value); value = BITSWAP64(value); return *this; }

	ByteBuffer& operator<<(const string &value);
	ByteBuffer& operator>>(string &value);

	ByteBuffer& operator<<(ByteBuffer &value);
	ByteBuffer& operator>>(ByteBuffer &value);

	ByteBuffer& operator<<(float value);
	ByteBuffer& operator>>(float &value);

	ByteBuffer& operator<<(double value);
	ByteBuffer& operator>>(double &value);

private:

	void _Write(const uint8 *src, size_t size);
	void _Read(uint8 *dest, size_t size);

	template <typename T> void _Write(T value) 	{ _Write((uint8*)&value, sizeof(T)); }
	template <typename T> void _Read(T &value)	{ _Read((uint8*)&value, sizeof(T)); }

private:

	size_t _rpos;
	size_t _wpos;
	vector<uint8> _storage;
};

class ByteBufferException : public Exception
{
public:

	ByteBufferException(string description) : Exception(description) {}
	virtual ~ByteBufferException() {}
};